package com.rmkj.trade.match.core;

import com.rmkj.trade.match.core.ob.ChangeData;
import com.rmkj.trade.match.core.ob.ChangeObservable;
import com.rmkj.trade.match.core.ob.ChangeObserver;
import com.rmkj.trade.match.core.ob.Changeable;
import com.rmkj.trade.match.data.DataListener;
import com.rmkj.trade.match.data.TickerData;
import com.rmkj.trade.match.data.TickerDataChangeable;
import com.rmkj.trade.match.data.TickerDataObserver;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.*;

/**
 * Created by Administrator on 2019/1/8.
 * 撮合人技能表
 */
public abstract class Matcher {

	private Map<Class, ChangeObservable> changeObservableMaps = new HashMap<>();
	private Map<Class, List<ChangeObserver>> changeObserverMaps = new HashMap<>();

	private List<DataListener<? extends ChangeData>> listeners = new ArrayList<>();

	public Matcher() {
		changeObservableMaps.put(TickerData.class, new ChangeObservable<TickerData>());
	}

	/**
	 * 下单
	 * @param direction
	 * @param owner
	 * @param production
	 * @param price
	 * @param amount
	 * @param token
	 */
	protected abstract void call(int direction, String owner, String production, String price, String amount, String token);

	/**
	 * 当前最新价格
	 * @return
	 */
	public abstract String lastPrice();

	/**
	 * 当前时间是否在交易时间
	 * @return
	 */
	public abstract boolean isOpen();

	/**
	 * 下卖单
	 * @param owner
	 * @param goodsCode
	 * @param price
	 * @param amount
	 * @param token
	 */
	public void sell(String owner, String goodsCode, String price, String amount, String token){
		if (isOpen())
			call(MatchTradeConstants.ORDER_DIRECTION_SELL, owner, goodsCode, price, amount, token);
	}

	/**
	 * 下买单
	 * @param owner
	 * @param goodsCode
	 * @param price
	 * @param amount
	 * @param token
	 */
	public void buy(String owner, String goodsCode, String price, String amount, String token){
		if (isOpen())
			call(MatchTradeConstants.ORDER_DIRECTION_BUY, owner, goodsCode, price, amount, token);
	}

	/**
	 * 添加监听
	 * @param dataListener
	 */
	public void addListener(DataListener<? extends ChangeData> dataListener){
		// TODO 不严谨
		Type clazz = dataListener.getClass().getGenericInterfaces()[0];
		if (clazz != null) {
			Type[] actualTypeArguments = ((ParameterizedType) clazz).getActualTypeArguments();
			for(Type t : actualTypeArguments){
				Class classKey = (Class) t;
				if(addListener(classKey, dataListener)){
					return;
				}
			}
		}

	}

	/**
	 *
	 * @param classKey
	 * @param dataListener
	 */
	public boolean addListener(Class<? extends ChangeData> classKey, DataListener<? extends ChangeData> dataListener){
		if(changeObserverMaps.containsKey(classKey)){
			changeObserverMaps.get(classKey).forEach(it -> it.addListener(dataListener));
			listeners.add(dataListener);
			return true;
		}
		return false;
	}



	/**
	 * 添加观察者
	 * @param clazz
	 * @param clazz1 为空时，默认总是改变的
	 */
	protected synchronized void addOb(Class<? extends ChangeObserver> clazz, Class<? extends Changeable> clazz1){
		// TODO 不严谨
		Class classKey = (Class) ((ParameterizedType)clazz.getGenericSuperclass()).getActualTypeArguments()[0];
		if(changeObservableMaps.containsKey(classKey)){
			try {
				if(!changeObserverMaps.containsKey(classKey)){
					changeObserverMaps.put(classKey, new ArrayList<>());
				}
				ChangeObserver ob = (ChangeObserver)clazz.getConstructors()[0].newInstance(changeObservableMaps.get(classKey), clazz1.newInstance());
				changeObserverMaps.get(classKey).add(ob);
			} catch (InstantiationException e) {
				e.printStackTrace();
			} catch (IllegalAccessException e) {
				e.printStackTrace();
			} catch (InvocationTargetException e) {
				e.printStackTrace();
			}
		}
	}

	/**
	 * 清除观察者
	 */
	protected synchronized void clearOb(){
		changeObservableMaps.forEach((clazz, observer) -> {
			if(changeObserverMaps.containsKey(clazz)){
				changeObserverMaps.get(clazz).forEach(ob -> {
					observer.deleteObserver(ob);
				});
			}
		});
	}

	/**
	 * 初始化数据
	 * @param data
	 */
	protected void init(ChangeData data){
		if(changeObservableMaps.containsKey(data.getClass())){
			changeObservableMaps.get(data.getClass()).initData(data);
		}
	}

	/**
	 * 数据变更通知
	 * @param data
	 */
	protected void notify(ChangeData data){
		if(changeObservableMaps.containsKey(data.getClass())){
			changeObservableMaps.get(data.getClass()).setData(data);
		}
	}

	/**
	 *  添加默认的观察者
	 */
	protected void addDefaultObs(){
		addOb(TickerDataObserver.class, TickerDataChangeable.class);
	}

}
